defmodule FileHandling do
  def read_lines filename do
    File.stream!(filename)
    |> Stream.map(&String.trim_trailing/1)
    |> Enum.to_list
  end
end

defmodule ListProcessing do
  # separate lists at "" element
  def split_at_nil(nil, acc) do {:cont, Enum.reverse(acc), []} end
  def split_at_nil(elem, acc) do {:cont, [elem | acc]} end

  def remaining_elems [] do {:cont, []} end
  def remaining_elems other do {:cont, Enum.reverse(other), []} end

  def lines_to_integer enum do
    enum |> Enum.map(
      fn
        "" -> nil
        number_string -> String.to_integer(number_string, 10)
      end
    )
  end
end

# Need to wrap the code in a function to be able to see the struct.
defmodule Main do
  def main do
    lines = FileHandling.read_lines "input"
    calories = ListProcessing.lines_to_integer lines
    calories_grouped = Enum.chunk_while(
      calories,
      [],
      &ListProcessing.split_at_nil/2,
      &ListProcessing.remaining_elems/1
    )
    calories_summed_per_elf = Enum.map(
      calories_grouped,
      fn [] -> 0; calories -> Enum.sum calories end
    )
    calories_sorted_per_elf = Enum.sort(
      calories_summed_per_elf,
      fn calories1, calories2 -> calories1 >= calories2 end
    )
    result = Enum.take(calories_sorted_per_elf, 3) |> Enum.sum
    IO.puts("calories carried by the 3 elves carring the most calories summed: #{result}")
  end
end

Main.main
